﻿@using Gurux.DLMS.AMI.Module
@using Gurux.DLMS.AMI.Shared
@using Gurux.DLMS.AMI.Shared.DIs
@using Gurux.DLMS.AMI.Shared.Enums
@using Microsoft.AspNetCore.Authorization
@using Microsoft.AspNetCore.Components.WebAssembly.Authentication
@using Gurux.DLMS.AMI.Shared.DTOs
@using Gurux.DLMS.AMI.Shared.Rest
@using Microsoft.AspNetCore.SignalR.Client
@using Gurux.DLMS.AMI.Client.Pages.Agent
@using System.Text.Json
@using System.Text.Encodings.Web;
@using Gurux.DLMS.AMI.Shared.DTOs.Agent;
    using Gurux.DLMS.AMI.Shared.DTOs.Script;

@attribute [Authorize(Roles = "Admin, AgentManager")]
@inject NavigationManager NavigationManager
@inject HttpClient Http
@inject IGXNotifier Notifier

@if (Active != null)
{
    <EditForm Model="@Active">
        <DataAnnotationsValidator />
        <ValidationSummary />
        <GXValidator @ref="_agentValidator" OnValidate="OnValidate" />
        <div class="row">
            <div style="width:100%">
                <div class="form-group">
                    <label>@Properties.Resources.Name</label>
                    <InputText id="name" disabled="@IsDeleting" class="form-control"
                               @bind-Value="Active.Name" />
                    <ValidationMessage For="@(() => Active.Name)" />
                </div>
                <div class="form-group">
                    <label>@Properties.Resources.Description</label>
                    <InputText id="name" disabled="@IsDeleting" class="form-control"
                               @bind-Value="Active.Description" />
                </div>
                <div class="form-group">
                    <label>@Properties.Resources.Version</label>
                    @if (string.IsNullOrEmpty(Active.Version))
                    {
                        <input class="form-control" type="text" readonly="readonly" value="@Properties.Resources.CustomBuild" />
                    }
                    else
                    {
                        <input class="form-control" type="text" readonly="readonly" value="@Active.Version" />
                    }
                </div>
                @if (!string.IsNullOrEmpty(Active.SerialPorts))
                {
                    <div class="form-group">
                        <label style="margin:auto">@Properties.Resources.SerialPort</label>
                        <select class="form-select" @bind="@Active.SerialPort">
                            @foreach (string it in GetSerialPorts())
                            {
                                <option value="@it">@it</option>
                            }
                        </select>
                    </div>
                }
            </div>
        </div>
    </EditForm>
    <TabControl>
        <TabTextTemplate>
            <span class=@context.Icon aria-hidden="true"></span>
            @context.Text
        </TabTextTemplate>
        <ChildContent>
            <TabPage Text="Reader" Icon="oi oi-transfer">
                <div style="position: relative; width: 100%; ">
                    <ReaderOptions Settings="@ReaderSettings"
                                   @ref="_readerOptions"
                                   @bind-SerialPort="@Active.SerialPort"></ReaderOptions>
                </div>
            </TabPage>
            <TabPage Text="Push events" Icon="oi oi-flash">
                <div style="position: relative; width: 100%; ">
                    <NotifyOptions Settings="@NotifySettings"
                                   Scripts="@scripts"
                                   @ref="_notifyOptions"
                                   @bind-SerialPort="@Active.SerialPort"></NotifyOptions>
                </div>
            </TabPage>
            <TabPage Text="Auto connect" Icon="oi oi-loop">
                <div style="position: relative; width: 100%; ">
                    <AutoConnectOptions Settings="@ListenerSettings"
                                        Scripts="@scripts"
                                        @ref="_autoConnectOptions"
                                        @bind-SerialPort="@Active.SerialPort"></AutoConnectOptions>
                </div>
            </TabPage>
        </ChildContent>
    </TabControl>
    <EditForm Model="@Active">
        <DataAnnotationsValidator />
        <ValidationSummary />
        <div class="row">
            <div style="width:100%">
                @if (Active.Detected != null)
                {
                    <div class="form-group">
                        <label>@Properties.Resources.Detected</label>
                        <InputDate Type="@InputDateType.DateTimeLocal" id="detected" readonly="readonly" class="form-control"
                                   @bind-Value="Active.Detected" />
                    </div>
                }
                <div class="form-group">
                    <label>@Properties.Resources.CreationTime</label>
                    <InputDate Type="@InputDateType.DateTimeLocal" id="creationTime" readonly="readonly" class="form-control"
                               @bind-Value="Active.CreationTime" />
                </div>
                @if (Active.Updated != null)
                {
                    <div class="form-group">
                        <label>@Properties.Resources.Updated</label>
                        <InputDate Type="@InputDateType.DateTimeLocal" id="updated" readonly="readonly" class="form-control"
                                   @bind-Value="Active.Updated" />
                    </div>
                }
                @if (Active.Removed != null)
                {
                    <div class="form-group">
                        <label>@Properties.Resources.Remove</label>
                        <InputDate Type="@InputDateType.DateTimeLocal" id="remove" class="form-control"
                                   @bind-Value="Active.Removed" />
                    </div>
                }
                @if (action == CrudAction.Delete)
                {
                    <hr />
                    <p>
                    </p>
                    <div class="form-group">
                        <InputRadioGroup @bind-Value="DeleteTarget">
                            <InputRadio Value="false">
                            </InputRadio>
                            <label>@Properties.Resources.TargetDisableQuestion</label><br>
                            <InputRadio Value="true">
                            </InputRadio>
                            <label>@Properties.Resources.TargetDeleteQuestion</label>
                        </InputRadioGroup>
                        <br />
                    </div>
                }
            </div>
        </div>
    </EditForm>
}
@code {
    [CascadingParameter]
    private AgentTab? Parent { get; set; }

    private GXAgent? _active;

    private GXAgent? Active
    {
        get
        {
            if (Parent?.Active != null)
            {
                return Parent.Active;
            }
            return _active;
        }
    }

    private List<string> GetSerialPorts()
    {
        List<string> list = new();
        if (!string.IsNullOrEmpty(Active?.SerialPorts))
        {
            list.Add("");
            list.AddRange(Active.SerialPorts.Split(";"));
        }
        return list;
    }

    /// <summary>
    /// User action.
    /// </summary>
    [Parameter]
    public string? Action { get; set; }

    private CrudAction action;
    /// <summary>
    /// Selected item.
    /// </summary>
    [Parameter]
    public Guid? Id { get; set; }

    private bool DeleteTarget;
    public string? IsDeleting
    {
        get
        {
            if (action != CrudAction.Delete)
            {
                return null;
            }
            return "disabled";
        }
    }
    private GXValidator? _agentValidator;
    /// <summary>
    /// Validate the agent content.
    /// </summary>
    /// <param name="sender"></param>
    private void OnValidate(GXValidator sender)
    {
        if (Active != null && string.IsNullOrEmpty(Active.Name))
        {
            sender.AddError(() => Active.Name, "Invalid name.");
        }
        _readerOptions?.Validate(sender);
        _notifyOptions?.Validate(sender);
        _autoConnectOptions?.Validate(sender);
    }

    ReaderSettings? ReaderSettings { get; set; }
    NotifySettings? NotifySettings { get; set; }
    ListenerSettings? ListenerSettings { get; set; }

    ReaderOptions? _readerOptions;
    NotifyOptions? _notifyOptions;
    AutoConnectOptions? _autoConnectOptions;

    //Available scripts.
    private GXScript[]? scripts;

    private List<GXScript> Scripts = new();

    /// <summary>
    /// Update agent settings after they are read from the server.
    /// </summary>
    public void Update()
    {
        if (!string.IsNullOrEmpty(Active?.ReaderSettings))
        {
            ReaderSettings = JsonSerializer.Deserialize<ReaderSettings>
                (Active.ReaderSettings);
        }
        if (!string.IsNullOrEmpty(Active?.NotifySettings))
        {
            NotifySettings = JsonSerializer.Deserialize<NotifySettings>
                (Active.NotifySettings);
        }
        if (!string.IsNullOrEmpty(Active?.ListenerSettings))
        {
            ListenerSettings = JsonSerializer.Deserialize<ListenerSettings>
                (Active.ListenerSettings);
        }
        StateHasChanged();
    }

    protected override async Task OnInitializedAsync()
    {
        try
        {
            Notifier.ProgressStart();
            Notifier.ClearStatus();
            Notifier.Clear();
            if (Active == null && Id != null)
            {
                //Get agent data.
                var tmp = (await Http.GetAsJsonAsync<GetAgentResponse>
                    (string.Format("api/Agent?id={0}", Id)));
                if (tmp?.Item != null)
                {
                    _active = tmp.Item;
                }
                else
                {
                    NavigationManager.NavigateTo("404");
                }
            }
            if (Active == null)
            {
                throw new ArgumentException(Properties.Resources.InvalidTarget);
            }
            action = ClientHelpers.GetAction(Action);
            if (action == CrudAction.Delete)
            {
                Notifier.AddMenuItem(new GXMenuItem() { Text = Properties.Resources.Remove, Icon = "oi oi-trash", OnClick = OnSave });
            }
            else
            {
                Notifier.AddMenuItem(new GXMenuItem() { Text = Properties.Resources.Save, Icon = "oi oi-pencil", OnClick = OnSave });
            }
            Notifier.AddMenuItem(new GXMenuItem() { Text = Properties.Resources.Cancel, Icon = "oi oi-action-undo", OnClick = OnCancel });
            Notifier.UpdateButtons();
            ListScripts req = new ListScripts();
            var ret = await Http.PostAsJson<ListScriptsResponse>
                ("api/Script/List", req);
            scripts = ret.Scripts;

            if (!string.IsNullOrEmpty(Active?.ReaderSettings))
            {
                ReaderSettings = JsonSerializer.Deserialize<ReaderSettings>
                    (Active.ReaderSettings);
            }
            else
            {
                ReaderSettings = new ReaderSettings();
            }
            if (!string.IsNullOrEmpty(Active?.NotifySettings))
            {
                NotifySettings = JsonSerializer.Deserialize<NotifySettings>
                    (Active.NotifySettings);
            }
            else
            {
                NotifySettings = new NotifySettings();
            }
            if (!string.IsNullOrEmpty(Active?.ListenerSettings))
            {
                ListenerSettings = JsonSerializer.Deserialize<ListenerSettings>
                    (Active.ListenerSettings);
            }
            else
            {
                ListenerSettings = new ListenerSettings();
            }
        }
        catch (AccessTokenNotAvailableException exception)
        {
            exception.Redirect();
        }
        catch (Exception ex)
        {
            Notifier?.ProcessError(ex);
        }
        finally
        {
            Notifier?.ProgressEnd();
        }
    }

    /// <summary>
    /// Save agent.
    ///</summary>
    public async void OnSave()
    {
        try
        {
            _agentValidator?.ClearErrors();
            if (Active == null)
            {
                throw new Exception(Properties.Resources.InvalidTarget);
            }
            if (_agentValidator != null && !_agentValidator.Validate())
            {
                return;
            }
            Notifier.ProgressStart();
            Notifier.ClearStatus();
            if (action == CrudAction.Delete)
            {
                await Http.PostAsJson<RemoveAgentResponse>
                    ("api/Agent/Delete", new RemoveAgent()
                        {
                            Ids = new Guid[] { Active.Id },
                            Delete = DeleteTarget
                        });
            }
            else
            {
                //This is needed to serialize special chars.
                var options = new JsonSerializerOptions
                    {
                        Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping,
                        WriteIndented = true
                    };
                Active.ReaderSettings = JsonSerializer.Serialize(ReaderSettings, options);
                Active.NotifySettings = JsonSerializer.Serialize(NotifySettings, options);
                Active.ListenerSettings = JsonSerializer.Serialize(ListenerSettings, options);
                string address;
                if (action == CrudAction.Create)
                {
                    address = "api/Agent/Add";
                }
                else if (action == CrudAction.Update)
                {
                    address = "api/Agent/Update";
                }
                else
                {
                    throw new Exception(Properties.Resources.InvalidTarget);
                }
                await Http.PostAsJson<UpdateAgentResponse>
                    (address, new UpdateAgent()
                        {
                            Agents = new GXAgent[] { Active }
                        }
                    );
            }
            ClientHelpers.NavigateToLastPage(NavigationManager, Notifier);
        }
        catch (AccessTokenNotAvailableException exception)
        {
            exception.Redirect();
        }
        catch (Exception ex)
        {
            Notifier?.ProcessError(ex);
        }
        finally
        {
            Notifier?.ProgressEnd();
        }
    }

    /// <summary>
    /// Cancel update.
    ///</summary>
    private void OnCancel()
    {
        ClientHelpers.NavigateToLastPage(NavigationManager, Notifier);
    }
}
